package com.hmilyylimh.cloud.monster.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hmilyylimh.cloud.facade.demo.DemoFacade;
import com.hmilyylimh.cloud.facade.fanhua.HereticalReq;
import com.hmilyylimh.cloud.facade.user.bean.UserInfo;
import groovy.lang.GroovyClassLoader;
import org.apache.commons.codec.binary.Base64;
import org.apache.dubbo.config.annotation.DubboService;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

/**
 * <h1><a href="https://time.geekbang.org/column/intro/100312101">极客专栏地址：https://time.geekbang.org/column/intro/100312101</a></h1><br/><h1><a href="https://gitee.com/ylimhhmily/GeekDubbo3Tutorial">案例代码地址：https://gitee.com/ylimhhmily/GeekDubbo3Tutorial</a></h1>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2022-10-31
 */
@DubboService
public class MonsterFacadeImpl implements MonsterFacade, ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private static final GroovyClassLoader groovyClassLoader;

    static {
        CompilerConfiguration config = new CompilerConfiguration();
        config.setSourceEncoding("utf-8");
        groovyClassLoader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader(),config);
    }

    @Override
    public AbstractResponse heretical(HereticalReq req){

        byte[] bytes1 = Base64.decodeBase64(req.getJavaCode());

        // 编译 Java 代码，然后变成 JVM 可识别的 Class 对象信息
        Class<?> javaClass = compile(new String(bytes1));
        // 为 Class 对象信息，自定义一个名称，将来创建 Spring 单例对象要用到
        String beanName = "Custom" + javaClass.getSimpleName();

        Object bean = null;
        try {
            bean = applicationContext.getBean(beanName);
            if (bean == null) {
                // 通过 Spring 来创建单例对象
                generateSpringBean(beanName, javaClass);
            }
        } catch (BeansException e) {
            if (bean == null) {
                // 通过 Spring 来创建单例对象
                generateSpringBean(beanName, javaClass);
            }
        }

        // 获取 beanName 对应的单例对象
        DemoFacade runnable = (DemoFacade) applicationContext.getBean(beanName);

        Object reqParamsMap = req.getReqParamsMap();



        Object parse = JSONObject.parse(JSONObject.toJSONString(reqParamsMap));

        UserInfo userInfo = JSONObject.parseObject(JSONObject.toJSONString(reqParamsMap), UserInfo.class);

        System.out.println("1111  " + parse.toString());
        // 执行单例对象的方法即可
        String s = runnable.sayUser(userInfo);

        System.out.println(s);
        // 返回结果
        return new AbstractResponse(s);
    }

    private Class<?> compile(String javaCode){
        return groovyClassLoader.parseClass(javaCode);
    }

    private void generateSpringBean(String beanName, Class<?> javaClass){
        // 构建 Bean 定义对象
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(javaClass);
        AbstractBeanDefinition rawBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();

        // 将 bean 移交给 Spring 去管理
        ConfigurableApplicationContext appCtx =
                (ConfigurableApplicationContext)SpringContextUtils.getContext();

        applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(rawBeanDefinition, beanName);

        ((BeanDefinitionRegistry)((AbstractApplicationContext)applicationContext).getBeanFactory()).registerBeanDefinition(beanName, rawBeanDefinition);
    }

    public static void main(String[] args) {

        String str = "import com.alibaba.fastjson.JSON;\n" +
                "import com.hmilyylimh.cloud.facade.demo.DemoFacade;\n" +
                "import com.hmilyylimh.cloud.facade.user.bean.UserInfo;\n" +
                "\n" +
                "public class DemoFanHuaImpl implements DemoFacade {\n" +
                "\n" +
                "    @Override\n" +
                "    public String sayHello(String name) { return null; }\n" +
                "\n" +
                "    @Override\n" +
                "    public String sayUser(UserInfo userInfo) {\n" +
                "        System.out.println(\"点点直连\");\n" +
                "        return JSON.toJSONString(userInfo);\n" +
                "    }\n" +
                "}";

        byte[] bytes = Base64.encodeBase64(str.getBytes());
        System.out.println(bytes);
        System.out.println("-----------------");
        String s = new String(bytes);
        System.out.println(s);
        System.out.println("-----------------");

        byte[] bytes1 = Base64.decodeBase64(s);
        System.out.println(bytes1);
        System.out.println(new String(bytes1));

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;
    }

    //////////////////////////////////////////////////////////////////////////////////
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已
    // 下面的空实现仅示意代码思路而已

    private static class SpringContextUtils {
        public static Object getBean(String beanName) {
            return applicationContext.getBean(beanName);
        }

        public static Object getContext() {
            return null;
        }
    }

    private class MonsterAction {
    }

    private class MonsterInvokeRunnable {
        public Object run(Object reqParamsMap) {
            return null;
        }
    }
}
